import random
import socket
import struct
import threading
import time
import tkinter as tk
from datetime import datetime
from tkinter import scrolledtext, messagebox

import ttkbootstrap as ttk
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


@annotate(ClassInfo(name="网速测试", category="tool"))
class NetSpeedView(View):
    """设置视图"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 核心变量
        self.role = tk.StringVar(value="client")  # client 或 server
        self.server_ip = tk.StringVar(value="127.0.0.1")
        self.server_port = tk.IntVar(value=5000)
        self.packet_size = tk.IntVar(value=1024)  # 数据包大小，单位：字节
        self.test_duration = tk.IntVar(value=10)  # 测试时长，单位：秒
        self.concurrency = tk.IntVar(value=5)  # 并发连接数

        # 测试状态变量
        self.is_running = False
        self.server_socket = None
        self.client_sockets = []
        self.test_results = {
            "start_time": None,
            "end_time": None,
            "total_packets_sent": 0,
            "total_packets_received": 0,
            "total_bytes_sent": 0,
            "total_bytes_received": 0,
            "lost_packets": 0,
            "average_latency": 0,
            "latency_list": []
        }

        # 创建UI
        self._create_widgets()

    def _create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self, padding=15)
        main_frame.pack(fill=BOTH, expand=YES)

        # 角色选择区域
        role_frame = ttk.LabelFrame(main_frame, text="角色选择", padding=10)
        role_frame.pack(fill=X, pady=5)

        ttk.Radiobutton(role_frame, text="客户端", variable=self.role, value="client",
                        command=self.update_ui_based_on_role).pack(side=LEFT, padx=20, pady=5)
        ttk.Radiobutton(role_frame, text="服务器", variable=self.role, value="server",
                        command=self.update_ui_based_on_role).pack(side=LEFT, padx=20, pady=5)

        # 连接配置区域
        config_frame = ttk.LabelFrame(main_frame, text="连接配置", padding=10)
        config_frame.pack(fill=X, pady=5)

        config_grid = ttk.Frame(config_frame)
        config_grid.pack(fill=X, expand=YES)

        ttk.Label(config_grid, text="服务器IP:").grid(row=0, column=0, padx=5, pady=10, sticky=E)
        self.ip_entry = ttk.Entry(config_grid, textvariable=self.server_ip, width=20)
        self.ip_entry.grid(row=0, column=1, padx=5, pady=10, sticky=W)

        ttk.Label(config_grid, text="端口:").grid(row=0, column=2, padx=5, pady=10, sticky=E)
        self.port_entry = ttk.Entry(config_grid, textvariable=self.server_port, width=10)
        self.port_entry.grid(row=0, column=3, padx=5, pady=10, sticky=W)

        # 测试参数配置区域
        param_frame = ttk.LabelFrame(main_frame, text="测试参数", padding=10)
        param_frame.pack(fill=X, pady=5)

        param_grid = ttk.Frame(param_frame)
        param_grid.pack(fill=X, expand=YES)

        ttk.Label(param_grid, text="数据包大小 (字节):").grid(row=0, column=0, padx=5, pady=10, sticky=E)
        ttk.Entry(param_grid, textvariable=self.packet_size, width=10).grid(row=0, column=1, padx=5, pady=10, sticky=W)

        ttk.Label(param_grid, text="测试时长 (秒):").grid(row=0, column=2, padx=5, pady=10, sticky=E)
        ttk.Entry(param_grid, textvariable=self.test_duration, width=10).grid(row=0, column=3, padx=5, pady=10,
                                                                              sticky=W)

        ttk.Label(param_grid, text="并发连接数:").grid(row=0, column=4, padx=5, pady=10, sticky=E)
        ttk.Entry(param_grid, textvariable=self.concurrency, width=10).grid(row=0, column=5, padx=5, pady=10, sticky=W)

        # 控制按钮区域
        btn_frame = ttk.Frame(main_frame, padding=10)
        btn_frame.pack(fill=X, pady=5)

        self.start_btn = ttk.Button(
            btn_frame,
            text="开始测试",
            command=self.start_test,
            bootstyle=SUCCESS,
            width=15
        )
        self.start_btn.pack(side=LEFT, padx=10)

        self.stop_btn = ttk.Button(
            btn_frame,
            text="停止测试",
            command=self.stop_test,
            bootstyle=DANGER,
            width=15,
            state=DISABLED
        )
        self.stop_btn.pack(side=LEFT, padx=10)

        # 进度条
        self.progress = ttk.Progressbar(main_frame, mode=DETERMINATE, length=100)
        self.progress.pack(fill=X, pady=5)

        # 测试结果区域
        result_frame = ttk.LabelFrame(main_frame, text="测试结果", padding=10)
        result_frame.pack(fill=BOTH, expand=YES, pady=5)

        result_grid = ttk.Frame(result_frame)
        result_grid.pack(fill=BOTH, expand=YES)

        # 结果指标
        metrics_frame = ttk.Frame(result_grid)
        metrics_frame.pack(fill=X, pady=5)

        self.metrics = {
            "状态": tk.StringVar(value="就绪"),
            "已发送数据": tk.StringVar(value="0 MB"),
            "已接收数据": tk.StringVar(value="0 MB"),
            "发送速度": tk.StringVar(value="0 Mbps"),
            "接收速度": tk.StringVar(value="0 Mbps"),
            "丢包率": tk.StringVar(value="0%"),
            "平均延迟": tk.StringVar(value="0 ms")
        }

        row_idx = 0
        col_idx = 0
        for i, (name, var) in enumerate(self.metrics.items()):
            ttk.Label(metrics_frame, text=f"{name}:").grid(row=row_idx, column=col_idx, padx=15, pady=5, sticky=E)
            ttk.Label(metrics_frame, textvariable=var, font=("Arial", 10, "bold")).grid(
                row=row_idx, column=col_idx + 1, padx=15, pady=5, sticky=W)

            col_idx += 2
            if col_idx >= 6:  # 每行显示3组指标
                col_idx = 0
                row_idx += 1

        # 日志区域
        log_frame = ttk.LabelFrame(result_grid, text="测试日志", padding=10)
        log_frame.pack(fill=BOTH, expand=YES, pady=5)

        self.log_text = scrolledtext.ScrolledText(
            log_frame,
            wrap=tk.WORD,
            height=10,
            font=('SimHei', 10)
        )
        self.log_text.pack(fill=BOTH, expand=YES)
        self.log_text.config(state=DISABLED)

        # 初始化UI状态
        self.update_ui_based_on_role()
        self.log_message("欢迎使用网络测速工具")
        self.log_message("请选择角色、配置参数，然后点击开始测试")

    def update_ui_based_on_role(self):
        """根据选择的角色更新UI状态"""
        role = self.role.get()
        if role == "server":
            self.ip_entry.config(state=DISABLED)
            self.log_message("已切换到服务器模式")
        else:
            self.ip_entry.config(state=NORMAL)
            self.log_message("已切换到客户端模式")

    def log_message(self, message):
        """在日志区域添加消息"""
        timestamp = datetime.now().strftime("%H:%M:%S")
        self.log_text.config(state=NORMAL)
        self.log_text.insert(END, f"[{timestamp}] {message}\n")
        self.log_text.see(END)  # 滚动到最新内容
        self.log_text.config(state=DISABLED)

    def update_metrics(self):
        """更新测试指标显示"""
        # 计算时间差（秒）
        if not self.test_results["start_time"]:
            return

        elapsed = time.time() - self.test_results["start_time"]
        if elapsed <= 0:
            elapsed = 1

        # 转换字节为MB
        sent_mb = self.test_results["total_bytes_sent"] / (1024 * 1024)
        received_mb = self.test_results["total_bytes_received"] / (1024 * 1024)

        # 转换为Mbps (1字节 = 8比特)
        send_speed = (self.test_results["total_bytes_sent"] * 8) / (1024 * 1024 * elapsed)
        receive_speed = (self.test_results["total_bytes_received"] * 8) / (1024 * 1024 * elapsed)

        # 计算丢包率
        if self.test_results["total_packets_sent"] > 0:
            loss_rate = (self.test_results["lost_packets"] / self.test_results["total_packets_sent"]) * 100
        else:
            loss_rate = 0

        # 计算平均延迟
        if self.test_results["latency_list"]:
            avg_latency = sum(self.test_results["latency_list"]) / len(self.test_results["latency_list"])
        else:
            avg_latency = 0

        # 更新显示
        self.metrics["已发送数据"].set(f"{sent_mb:.2f} MB")
        self.metrics["已接收数据"].set(f"{received_mb:.2f} MB")
        self.metrics["发送速度"].set(f"{send_speed:.2f} Mbps")
        self.metrics["接收速度"].set(f"{receive_speed:.2f} Mbps")
        self.metrics["丢包率"].set(f"{loss_rate:.2f}%")
        self.metrics["平均延迟"].set(f"{avg_latency:.2f} ms")

        # 更新进度条
        if self.is_running and self.test_duration.get() > 0:
            progress = min(100, (elapsed / self.test_duration.get()) * 100)
            self.progress['value'] = progress

    def start_test(self):
        """开始网络测试"""
        # 验证参数
        try:
            port = self.server_port.get()
            if not (1024 <= port <= 65535):
                messagebox.showerror("参数错误", "端口号必须在1024-65535之间")
                return

            if self.packet_size.get() < 1 or self.packet_size.get() > 1048576:
                messagebox.showerror("参数错误", "数据包大小必须在1-1048576字节之间")
                return

            if self.test_duration.get() < 1 or self.test_duration.get() > 300:
                messagebox.showerror("参数错误", "测试时长必须在1-300秒之间")
                return

            if self.concurrency.get() < 1 or self.concurrency.get() > 100:
                messagebox.showerror("参数错误", "并发连接数必须在1-100之间")
                return
        except:
            messagebox.showerror("参数错误", "请检查输入参数")
            return

        # 重置测试结果
        self.test_results = {
            "start_time": time.time(),
            "end_time": None,
            "total_packets_sent": 0,
            "total_packets_received": 0,
            "total_bytes_sent": 0,
            "total_bytes_received": 0,
            "lost_packets": 0,
            "average_latency": 0,
            "latency_list": []
        }

        self.is_running = True
        self.start_btn.config(state=DISABLED)
        self.stop_btn.config(state=NORMAL)
        self.progress['value'] = 0
        self.metrics["状态"].set("测试中...")

        # 根据角色启动不同的测试
        if self.role.get() == "server":
            self.log_message("启动服务器模式...")
            threading.Thread(target=self.start_server, daemon=True).start()
        else:
            self.log_message("启动客户端模式...")
            threading.Thread(target=self.start_client, daemon=True).start()

        # 启动指标更新线程
        threading.Thread(target=self.update_metrics_loop, daemon=True).start()

    def stop_test(self):
        """停止网络测试"""
        self.is_running = False
        self.test_results["end_time"] = time.time()
        self.metrics["状态"].set("已停止")

        # 关闭服务器
        if self.server_socket:
            try:
                self.server_socket.close()
                self.log_message("服务器已关闭")
            except Exception as e:
                self.log_message(f"关闭服务器时出错: {str(e)}")

        # 关闭客户端连接
        for sock in self.client_sockets:
            try:
                sock.close()
            except:
                pass
        self.client_sockets = []

        # 更新UI状态
        self.start_btn.config(state=NORMAL)
        self.stop_btn.config(state=DISABLED)
        self.progress['value'] = 100

        self.log_message("测试已停止")

    def update_metrics_loop(self):
        """定期更新测试指标"""
        while self.is_running:
            self.update_metrics()
            time.sleep(0.5)

            # 检查测试是否超时
            if self.test_results["start_time"] and self.test_duration.get() > 0:
                elapsed = time.time() - self.test_results["start_time"]
                if elapsed >= self.test_duration.get():
                    self.after(0, self.stop_test)
                    break

        # 最后更新一次指标
        self.update_metrics()

    def start_server(self):
        """启动服务器"""
        try:
            # 创建TCP socket
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

            # 绑定到指定端口
            host = ""  # 监听所有可用接口
            port = self.server_port.get()
            self.server_socket.bind((host, port))

            # 开始监听
            self.server_socket.listen(self.concurrency.get())
            self.log_message(f"服务器已启动，监听端口 {port}...")
            self.log_message(f"等待客户端连接，最多支持 {self.concurrency.get()} 个并发连接")

            # 接受客户端连接并处理
            client_count = 0
            while self.is_running and client_count < self.concurrency.get():
                try:
                    self.server_socket.settimeout(1.0)  # 设置超时，以便能够响应停止命令
                    client_socket, client_address = self.server_socket.accept()
                    client_count += 1
                    self.log_message(f"客户端 {client_address} 已连接 ({client_count}/{self.concurrency.get()})")

                    # 启动线程处理客户端
                    threading.Thread(
                        target=self.handle_client,
                        args=(client_socket, client_address),
                        daemon=True
                    ).start()
                except socket.timeout:
                    continue
                except Exception as e:
                    if self.is_running:
                        self.log_message(f"接受连接时出错: {str(e)}")
                    break

        except Exception as e:
            self.log_message(f"启动服务器失败: {str(e)}")
            self.after(0, self.stop_test)

    def handle_client(self, client_socket, client_address):
        """处理客户端连接"""
        try:
            client_socket.settimeout(5.0)
            self.log_message(f"开始与 {client_address} 进行数据传输")

            while self.is_running:
                # 接收数据包
                data = client_socket.recv(4096)
                if not data:
                    break

                # 解析数据包 (包含时间戳)
                if len(data) >= 8:
                    timestamp = struct.unpack('d', data[:8])[0]
                    payload_size = len(data) - 8

                    # 计算延迟
                    latency = (time.time() - timestamp) * 1000  # 转换为毫秒

                    # 更新统计信息
                    self.test_results["total_packets_received"] += 1
                    self.test_results["total_bytes_received"] += len(data)
                    self.test_results["latency_list"].append(latency)

                # 发送响应 (回显数据)
                client_socket.sendall(data)
                self.test_results["total_packets_sent"] += 1
                self.test_results["total_bytes_sent"] += len(data)

        except Exception as e:
            if self.is_running:
                self.log_message(f"与 {client_address} 通信时出错: {str(e)}")
        finally:
            client_socket.close()
            self.log_message(f"与 {client_address} 的连接已关闭")

    def start_client(self):
        """启动客户端"""
        try:
            host = self.server_ip.get()
            port = self.server_port.get()
            self.log_message(f"尝试连接到服务器 {host}:{port}")

            # 创建多个客户端连接
            for i in range(self.concurrency.get()):
                try:
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    sock.connect((host, port))
                    self.client_sockets.append(sock)
                    self.log_message(f"客户端连接 {i + 1}/{self.concurrency.get()} 已建立")

                    # 启动线程发送数据
                    threading.Thread(
                        target=self.send_data,
                        args=(sock, i),
                        daemon=True
                    ).start()
                except Exception as e:
                    self.log_message(f"创建客户端连接 {i + 1} 失败: {str(e)}")
                    if not self.client_sockets:  # 如果所有连接都失败
                        self.after(0, self.stop_test)
                        return

            if not self.client_sockets:
                self.log_message("无法建立任何客户端连接")
                self.after(0, self.stop_test)

        except Exception as e:
            self.log_message(f"客户端启动失败: {str(e)}")
            self.after(0, self.stop_test)

    def send_data(self, sock, client_id):
        """发送测试数据"""
        packet_size = self.packet_size.get()
        start_time = time.time()

        try:
            sock.settimeout(5.0)
            self.log_message(f"客户端 {client_id + 1} 开始发送数据")

            while self.is_running:
                # 检查测试是否超时
                if time.time() - start_time >= self.test_duration.get():
                    break

                # 创建数据包: 8字节时间戳 + 随机数据
                timestamp = time.time()
                timestamp_bytes = struct.pack('d', timestamp)
                random_data = bytes([random.randint(0, 255) for _ in range(packet_size - 8)])
                data = timestamp_bytes + random_data

                # 发送数据
                sock.sendall(data)

                # 更新统计信息
                self.test_results["total_packets_sent"] += 1
                self.test_results["total_bytes_sent"] += len(data)

                # 等待响应
                start_wait = time.time()
                response = sock.recv(len(data))

                if response:
                    # 验证响应
                    if len(response) == len(data):
                        self.test_results["total_packets_received"] += 1
                        self.test_results["total_bytes_received"] += len(response)
                    else:
                        self.test_results["lost_packets"] += 1
                else:
                    self.test_results["lost_packets"] += 1

        except Exception as e:
            if self.is_running:
                self.log_message(f"客户端 {client_id + 1} 发送数据时出错: {str(e)}")
                self.test_results["lost_packets"] += 1
        finally:
            try:
                sock.close()
            except:
                pass
            self.log_message(f"客户端 {client_id + 1} 停止发送数据")

    def create_widgets(self):
        pass
